package cn.edu.swu.miniwebsvr.core;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
//HTTP 协议解析器。
//接收Socket输入流，将请求行、请求头和请求体解析成统一的Parameter对象。要求能解析GET的URL参数和POST的Body参数。
public class HttpParser {
    /**
     * 解析HTTP请求输入流，生成包含请求信息的Parameter对象
     * @param inputStream 客户端Socket的输入流（包含HTTP请求数据）
     * @return 封装了请求方法、URL、参数、请求头等信息的Parameter对象
     * @throws IOException 当输入流读取失败或解析异常时抛出
     */
    public static Parameter parse(InputStream inputStream) throws IOException {
        Parameter parameter = new Parameter();
        // 使用BufferedReader按行读取输入流（HTTP协议以行为单位分隔）
        BufferedReader reader = new BufferedReader(
                new InputStreamReader(inputStream, StandardCharsets.UTF_8)
        );
        // TODO: [学号/姓名]
        // 1. 读取并解析 HTTP 请求行 (e.g., GET /path?param=value HTTP/1.1)
        //    - 设置 parameter.setMethod()
        //    - 设置 parameter.setUrl()，并解析出 URL 参数 (e.g., ?param=value)，存入 parameter.urlParams
        String requestLine = reader.readLine();
        if (requestLine == null || requestLine.isEmpty()) {
            throw new IOException("无效的请求行");
        }
        parseRequestLine(requestLine, parameter);

        // 2. 循环读取并解析所有 HTTP 请求头 (e.g., Host: localhost:8080)
        //    - 存入 parameter.headers
        parseHeaders(reader, parameter);

        // 3. 根据请求方法 (Method) 和请求头 (Content-Length, Content-Type) 判断并读取请求体
        //    - 适用于 POST 请求，解析请求体中的参数，存入 parameter.bodyParams
        parseBody(reader, parameter);
        return parameter;
    }

    // TODO: [学号/姓名] 可以添加辅助方法来简化字符串解析和 URL 解码
    /**
     * 解析请求行，提取请求方法、URL路径及URL参数
     * @param requestLine 请求行字符串（如"GET /path?a=1&b=2 HTTP/1.1"）
     * @param parameter 存储解析结果的Parameter对象
     */
    private static void parseRequestLine(String requestLine, Parameter parameter) {
        String[] parts = requestLine.split("\\s+"); // 按空格拆分（至少1个空格）
        if (parts.length < 3) {
            throw new IllegalArgumentException("请求行格式错误: " + requestLine);
        }

        // 提取请求方法（如GET、POST）
        parameter.setMethod(parts[0]);

        // 提取URL并解析路径和参数（如"/path?a=1&b=2"）
        String url = parts[1];
        int queryIndex = url.indexOf('?'); // 查找URL中参数的起始位置（?）
        if (queryIndex != -1) {
            // 提取路径（?之前的部分）
            String path = url.substring(0, queryIndex);
            parameter.setUrl(path);
            // 解析URL参数（?之后的部分，如"a=1&b=2"）
            String queryParams = url.substring(queryIndex + 1);
            parameter.setUrlParams(extractQueryParams(queryParams));
        } else {
            // 无URL参数，直接设置路径为URL
            parameter.setUrl(url);
            parameter.setUrlParams(new HashMap<>()); // 初始化空参数
        }
    }
    /**
     * 解析请求头，将键值对存入Parameter的headers
     * @param reader 读取输入流的BufferedReader
     * @param parameter 存储解析结果的Parameter对象
     * @throws IOException 读取输入流失败时抛出
     */
    private static void parseHeaders(BufferedReader reader, Parameter parameter) throws IOException {
        Map<String, String> headers = new HashMap<>();
        String line;
        // 循环读取行，直到遇到空行（\r\n\r\n）表示请求头结束
        while ((line = reader.readLine()) != null && !line.isEmpty()) {
            int colonIndex = line.indexOf(':');
            if (colonIndex == -1) {
                continue; // 跳过格式错误的头（无冒号）
            }
            // 提取头名称（去除首尾空格）和头值（去除冒号后的空格）
            String key = line.substring(0, colonIndex).trim();
            String value = line.substring(colonIndex + 1).trim();
            headers.put(key, value);
        }
        parameter.setHeaders(headers);
    }

    /**
     * 解析请求体（针对POST请求），根据Content-Length和Content-Type提取参数
     * @param reader 读取输入流的BufferedReader
     * @param parameter 存储解析结果的Parameter对象
     * @throws IOException 读取输入流失败时抛出
     */
    private static void parseBody(BufferedReader reader, Parameter parameter) throws IOException {
        // 仅处理POST方法（通常POST才有请求体）
        if (!"POST".equalsIgnoreCase(parameter.getMethod())) {
            parameter.setBodyParams(new HashMap<>());
            return;
        }

        // 从请求头获取Content-Length（确定Body长度）
        Map<String, String> headers = parameter.getHeaders();
        String contentLengthStr = headers.getOrDefault("Content-Length", "0");
        int contentLength;
        try {
            contentLength = Integer.parseInt(contentLengthStr);
        } catch (NumberFormatException e) {
            contentLength = 0; // 无法解析长度时，默认无Body
        }

        // 读取Body内容（按Content-Length指定的字节数）
        if (contentLength > 0) {
            char[] bodyChars = new char[contentLength];
            int read = reader.read(bodyChars, 0, contentLength);
            if (read != contentLength) {
                throw new IOException("请求体长度与Content-Length不符");
            }
            String body = new String(bodyChars);

            // 解析Body参数（仅处理表单格式：application/x-www-form-urlencoded）
            String contentType = headers.getOrDefault("Content-Type", "");
            if (contentType.contains("application/x-www-form-urlencoded")) {
                parameter.setBodyParams(extractQueryParams(body));
            } else {
                // 其他格式（如JSON）可在此扩展，此处暂存原始Body
                parameter.setRawBody(body);
                parameter.setBodyParams(new HashMap<>());
            }
        } else {
            // 无Body时初始化空参数
            parameter.setBodyParams(new HashMap<>());
        }
    }

    /**
     * 解析查询字符串（如"a=1&b=2"）为键值对映射
     * @param query 待解析的查询字符串（URL参数或POST表单Body）
     * @return 解析后的键值对Map
     */
    private static Map<String, String> extractQueryParams(String query) {
        Map<String, String> params = new HashMap<>();
        if (query == null || query.isEmpty()) {
            return params;
        }

        // 按&分割参数（如"a=1&b=2" -> ["a=1", "b=2"]）
        String[] paramPairs = query.split("&");
        for (String pair : paramPairs) {
            // 按=分割键和值（如"a=1" -> ["a", "1"]）
            String[] keyValue = pair.split("=", 2); // 最多分割成2部分（处理值包含=的情况）
            if (keyValue.length < 2) {
                continue; // 跳过格式错误的参数（无值）
            }
            // URL解码（处理空格%20、中文编码等情况）
            String key = urlDecode(keyValue[0]);
            String value = urlDecode(keyValue[1]);
            params.put(key, value);
        }
        return params;
    }

    /**
     * 对URL编码的字符串进行解码（处理%20等转义字符）
     * @param encoded 编码后的字符串
     * @return 解码后的原始字符串
     */
    private static String urlDecode(String encoded) {
        try {
            // URL解码，使用UTF-8编码（HTTP标准编码）
            return URLDecoder.decode(encoded, StandardCharsets.UTF_8.name());
        } catch (Exception e) {
            // 解码失败时返回原始字符串
            return encoded;
        }
    }
}